#ifndef CNComms_H_
#define CNComms_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#ifdef linux
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <syslog.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <tchar.h>
#endif // linux

#define MAX_NCOMMS_PKT_SIZE 1024
#define MAX_NUM_SERVER_THREADS 1024

#pragma pack(push, 1)
typedef struct sNCOMMS {
    size_t msg_type;
    size_t msg_length;
    char *msg_data;
}type_sNCOMMS;
#pragma pack(pop)

typedef enum eNetCommsMsgTypes {
	systemlog = 19000,
	config_port = 19001,
	test_module = 19002,
	shared_cache = 19003,
	hw_ctl = 19004,
	mysqli_database = 19005,
	system_ctl = 19006,
	ui_ctl = 19007,
    fma_report = 19008,
	fma_critical_report = 19009,
	fma_error_report = 19010,
	fma_warning_report = 19011,
	fma_info_report = 19012,
	fma_auth_report = 19013,
	fma_fileintegrity_report = 19014,
	fma_flush_pipe = 19015,
	fma_system_memory_report = 19016,
	fma_unit_test_report = 19017,
	esta_bcr = 19018,
	este_bcr = 19019,
	estl_bcr = 19020,
	estn_bcr = 19021,
	estt_bcr = 19022,
	NUM_NET_COMMS_MSG_TYPES
}type_eNetCommsMsgTypes;

typedef enum eSocketType {
	SOCKET_TYPE_UDP,
	SOCKET_TYPE_TCP,
        NUM_SOCKET_TYPES
}type_eSocketType;

// NOTE: When sending data, the calling process must allocate & de-allocate the msg_data buffer.
// When receiving data, the CNComms object will allocate the msg_buffer. The calling process MUST deallocate the msg_buffer to avoid memory leakage.

using namespace std;

class CNComms {
 public:
	CNComms();
	~CNComms();

        int start_server(eNetCommsMsgTypes MYPORT, eSocketType socktype);
        int start_udp_server(eNetCommsMsgTypes MYPORT);
        string server_accept_inet_socket();
        int start_client(char *inet_address, eNetCommsMsgTypes MDEST_PORT, eSocketType socktype);
        void close_server(int threadNum);
        void close_connected_sockets();
        void close_client(int threadNum);
        void close_sockets();
        void close_socket(int dynamic_sock_fd);
        int send_ncomms_msg(struct sNCOMMS *);
        int recv_ncomms_msg(struct sNCOMMS *);
        int send_raw_ncomms_msg(char *data, int size);
        int send_raw_ncomms_msg(char *data, int size, int dynamic_sock_fd);
        int recv_raw_ncomms_msg(char *data, int size);
        int recv_raw_ncomms_msg(char *data, int size, int dynamic_sock_fd);

        bool socket_error[MAX_NUM_SERVER_THREADS];
 private:

        int create_server_inet_socket(int MYPORT, eSocketType socktype);
        int create_client_inet_socket(char *DEST_IP, int MYPORT, eSocketType socktype);
        int error(const char *msg, int errorcode);
        int send_data_header();
        int recv_data_header();
        int send_data_block();
        int recv_data_block();

		int sockfd, newsockfd, portno, active_socket_fd, dynamic_sock_fd[MAX_NUM_SERVER_THREADS];
		socklen_t clilen;
		char buffer[1024];
		struct sockaddr_in serv_addr, cli_addr;
		int n;
		struct hostent *server;
		bool bIsServer;

		//The message
		char *pMsg;
		int iMsgLength, iMsgIdx;
		string sresult;
};

#endif /*CNComms_H_*/
